#ifndef _MONITOR_H_
#define _MONITOR_H_

#include "core/Core.h"
#include "device/Timer.h"
#include "device/CLINT.h"
#include "device/Memory.h"
#include "device/Serial.h"
#include "device/Display.h"
#include "device/Keyboard.h"
#include "device/axi4/axi4_xbar.hpp"
#include "monitor/Expression.h"

#include <thread>

struct Command {
    std::string name;
    std::string description;
    std::function<int()> handler;
};

enum class State {
    RUN,
    PAUSE,
    END,
    ABORT,
    QUIT,
};

class Monitor {
private:
    bool batch_mode;
    // Bus bus;
    axi4_xbar<32,64,4> xbar;
    Core* core { nullptr };
    Memory* ram { nullptr };
    Serial* serial { nullptr };
    Timer* timer { nullptr };
    Keyboard* keyboard { nullptr };
    Display* display { nullptr };
    CLINT* clint { nullptr };
    Expression* expr { nullptr };
    State state { State::PAUSE };
    int halt_value;
    std::thread* device_thread { nullptr };
    IFDEF(CONFIG_DETECT, std::thread* detect_thread { nullptr };)
    
    std::vector<Command> cmd_table;
    int cmd_s();
    int cmd_c();
    int cmd_e();
    int cmd_x();
    int cmd_i();
    int cmd_r();
    int cmd_q();
    int cmd_v();
    int cmd_w();
    void cmd_table_init();
    std::istringstream iss;

    void device_init(const char* img_file);

public:
    Monitor(int argc, char *argv[]);
    ~Monitor();
    void run(size_t n = -1);
    int loop();
};

#endif
